package work.base.data.list;

import cn.hutool.core.collection.CollUtil;
import work.entity.User;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * ArrayList的简单使用
 *
 *
 * 注意
 *      1 取出List里面的单个对象, 修改它的值, List对象的值也会跟着变化
 *
 *
 */
public class ArrayListTest01 {

    public static void main(String[] args) {
        ArrayListTest01 arrayListTest01 = new ArrayListTest01();
        arrayListTest01.getSubList();
    }

    /**
     * List集合中添加元素
     */
    public void listAdd() {
        List<String> list1 = getStrList();
        // list在指定位置插入元素 参数index的值是新插入的元素在新的List的位置下标
        // index的值范围 0<= index <= list.size(), 否则会报错
        list1.add(4, "zzz");
        System.out.println("list1：" + list1);

        // 在指定的位置中插入c集合全部的元素，如果集合发生改变，则返回true，否则返回false。
        List<String> list2 = new ArrayList<>();
        List<String> list3 = new ArrayList<>();
        list2.add("星期一");
        list2.add("星期二");
        // 把list2元素插入到list1中索引位置为2处
        boolean isChange = list1.addAll(2, list2);
        System.out.println("list1：" + list1);
        System.out.println("list1集合是否发生变化：" + isChange);
        isChange = list1.addAll(2, list3);
        System.out.println("list1：" + list1);
        System.out.println("list1集合是否发生变化：" + isChange);
    }


    /**
     * List的遍历以及遍历过程中进行修改
     *
     * 使用方法
     * Iterator
     *      1 Iterator接口只有三个方法 hasNext(), next(), remove()
     *      2 迭代器可以在迭代的过程中删除集合的底层元素(使用Iterator接口的remove方法, 不建议使用集合本身的方法删除)
     *      3 Iterator接口虽然没有提供修改元素的方法, 但是如果集合里面是对象的话, 可以next()取出元素之后
     *        通过引用对象操作修改实际的内存对象, 这样子也可以修改原始的集合里面的数据
     *        (如果集合里面是基本类型就不行了, 当然也可以通过原始集合对象对数据进行修改比如 List的set()方法)
     * ListIterator
     *      1 ListIterator接口继承了Iterator, 额外增加了add(), set(), previous(), previousIndex(), nextIndex()方法
     *      2 实现了遍历集合时添加、修改和删除原始集合的元素, 还可以从后往前遍历, 获取前一个和后一个元素的位置下标
     * 两者总结
     *      1 集合里面如果是对象, 都可以通过引用对象修改集合里面实际的内存对象
     *      2 如果使用迭代器来遍历元素并且进行数据修改, 最好使用迭代器本身的方法 (更加安全)
     *      3 对集合里面的元素进行修改由三种方法
     *          集合本身的方法, 比如List的add(), set()方法
     *          集合内部对象的setXxx()方法, 直接修改元素的属性(对与 String和基本数据类型无法使用)
     *          通过ListIterator接口的set()方法
     * 注意
     *      1 for循环相对更加通用, 遍历的时候能使用集合本身的方法进行数据的修改
     *
     */
    public void listIteratorForEach() {
        // 集合里面是字符串
        List<String> list1 = getStrList();
        ListIterator<String> listIterator1 = list1.listIterator();
        while (listIterator1.hasNext()) {
            String next = listIterator1.next();
            if (next.equals("ccc")) {
                // 使用ListIterator接口的set()方法对原始集合的数据进行修改
                listIterator1.set("ccc_new");
            }
            if (next.equals("bbb")) {
                // 使用ListIterator接口的add()方法对原始集合进行添加新的元素
                listIterator1.add("bbb_after");
            }
        }
        // ListIterator从后往前遍历, 使用previous()从后往前遍历元素
        while (listIterator1.hasPrevious()) {
            System.out.print(listIterator1.previous() + " ");
        }
        System.out.println("");
        System.out.println("List遍历后的结果: " + list1);

        // 集合里面是对象
        List<User> list2 = getUserList();
        ListIterator<User> iterator2 = list2.listIterator();
        while (iterator2.hasNext()) {
            User next = iterator2.next();
            if (next.getName().equals("SML2")) {
                iterator2.set(new User("900", "沈明龙", "硕士"));
            }
        }
        list2.forEach(System.out::println);
    }


    /**
     * 最基本的 for循环
     *
     */
    public void forEach() {
        List<String> stringArray = getStrList();
        // 使用for的下标进行循环遍历也可以实现一边遍历一边添加
        for (int i = 0; i < stringArray.size(); i++) {
            String str = stringArray.get(i);
            if (str.equals("bbb")) {
                stringArray.add(4, "SML");
            }
        }
        System.out.println(stringArray);
    }

    /**
     * List遍历过程中修改对象
     * 使用 Iterator迭代器
     *
     */
    public void iteratorForEach() {
        List<String> list1 = getStrList();
        Iterator<String> iterator1 = list1.iterator();
        while (iterator1.hasNext()) {
            String next = iterator1.next();
            if (next.equals("bbb")) {
                // 通过原始的List集合对象的set()方法修改元素
                list1.set(list1.indexOf("bbb"), "SML");
            }
        }
        list1.forEach(System.out::println);

        List<User> list2 = getUserList();
        Iterator<User> iterator2 = list2.iterator();
        while (iterator2.hasNext()) {
            User next = iterator2.next();
            if (next.getName().equals("SML2")) {
                // 通过迭代器next()方法取出的元素(引用对象)来修改原始集合里面的实际内容
                next.setName("沈明龙");
            }
        }
        list2.forEach(System.out::println);
    }

    /**
     * 比较两个List的值
     */
    public void listCompare() {
        List<String> list1 = Stream.of("aaa", "bbb", "ccc", "ddd").collect(Collectors.toList());
        List<String> list2 = getStrList();
        System.out.println(CollUtil.isEqualList(list1, list2));
    }


    /**
     * 修改List里面对象的值
     */
    public void changeList() {
        List<User> userList = getUserList();
        Integer index = userList.indexOf(new User("20", "SML2", "初中"));
        userList.get(index).setName("沈明龙");
        userList.forEach(System.out::println);
    }

    /**
     * 获取子列表
     *
     * List接口的subList()不会改变原始数组的值
     * 获取的子列表的是下标为 fromIndex 到 (toIndex-1)的子列表
     *
     */
    public void getSubList() {
        List<String> strList = getStrList();
        List<String> subList = strList.subList(0, 2);
        System.out.println(strList);
    }

    /**
     * 构造对象列表
     *
     * @return 用户列表
     */
    public static List<User> getUserList() {
        User user1 = new User("10", "SML1", "小学");
        User user2 = new User("20", "SML2", "初中");
        User user3 = new User("30", "SML3", "高中");
        List<User> list = new ArrayList<>();
        list.add(user1);
        list.add(user2);
        list.add(user3);
        return list;
    }

    /**
     * 构造字符串列表
     *
     * @return 字符串列表
     */
    public static List<String> getStrList() {
        List<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add("ddd");
        return list;
    }
}
